#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "esp_timer.h"
#include "esp_log.h"

#include "dvc.h"
#include "dvc_log.h"
#include "http_server.h"
#include "config.h"
#include "ota.h"
#include "flashdb.h"
#include "wifi.h"

static const char *TAG = "DVC1006";

#define _malloc_(size) malloc(size)

#if CONFIG_DVC1006_CS == -1
#error "Configure CS pins for DVC1006"
#endif
#if CONFIG_DVC1006_ALERT == -1
#error "Configure ALERT pins for DVC1006"
#endif
#if CONFIG_DVC1006_WAKUP == -1
#error "Configure WAKUP pins for DVC1006"
#endif

spi_device_handle_t dvc_spi_handle = 0;

typedef uint16_t (*mqtt_cb_t)(void *user_data, uint8_t *buf, uint16_t buf_len);

extern void aes_enable(bool enable);
extern void log_push(uint8_t *data, uint8_t len);
extern void event_push(uint8_t *data, uint8_t len);
extern void event_get_all(fdb_tsl_cb cb);
extern void log_get_all(fdb_tsl_cb cb);
extern uint32_t sntp_get_timestamp(void);
extern void bemfa_send_msg(uint8_t type, uint8_t *buf, uint16_t buf_len, void *user_data, uint16_t (*get_data_cb)(void *user_data, uint8_t *buf, uint16_t buf_len));
extern void mqtt_send_msg(uint8_t type, uint8_t *buf, uint16_t buf_len, void *user_data, uint16_t (*get_data_cb)(void *user_data, uint8_t *buf, uint16_t buf_len));
extern bool user_call_reboot;
dvc_t gloab_dvc = 0;

uint8_t dvc_write_reg(void *user_data, uint32_t reg, uint8_t *data, uint8_t len)
{
    if (!user_data || !data || !len)
        return 1;
    esp_err_t ret;
    spi_device_handle_t handle = *(spi_device_handle_t *)user_data;
    if (!handle)
        return 1;

    uint8_t datas[16] = {0};
    memcpy(datas, &reg, 4);
    memcpy(&datas[4], data, len);
    len += 4;

    spi_transaction_t t = {
        .length = len * 8,
        .tx_buffer = datas,
    };

    spi_device_acquire_bus(handle, portMAX_DELAY);
    ret = spi_device_polling_transmit(handle, &t); // Transmit!
    spi_device_release_bus(handle);
    if (ret != ESP_OK)
    {
        ESP_LOGE(TAG, "Failed to write reg & data");
        return 1;
    }

    return 0;
}

uint8_t dvc_read_reg(void *user_data, uint32_t reg, uint8_t *data, uint8_t len)
{
    if (!user_data || !data || !len)
        return 1;
    esp_err_t ret;
    spi_device_handle_t handle = *(spi_device_handle_t *)user_data;
    if (!handle)
        return 1;

    spi_device_acquire_bus(handle, portMAX_DELAY);

    spi_transaction_t t = {
        .length = 4 * 8,
        .tx_buffer = &reg,
        .flags = SPI_TRANS_CS_KEEP_ACTIVE,
    };

    ret = spi_device_polling_transmit(handle, &t); // Transmit!
    if (ret != ESP_OK)
    {
        spi_device_release_bus(handle);
        ESP_LOGE(TAG, "Failed to write reg");
        return 1;
    }

    t.length = 0;
    t.tx_buffer = NULL;
    t.rxlength = len * 8;
    t.rx_buffer = data;
    t.flags &= ~SPI_TRANS_CS_KEEP_ACTIVE;
    ret = spi_device_polling_transmit(handle, &t); // Transmit!
    spi_device_release_bus(handle);
    if (ret != ESP_OK)
    {
        ESP_LOGE(TAG, "Failed to read data");
        return 1;
    }

    return 0;
}

static void increase_dvc1006_tick(void *arg)
{
    if (arg)
        dvc_tick(arg, 2);
}

void dvc_delay_ms(uint16_t ms)
{
    vTaskDelay(pdMS_TO_TICKS(ms));
}

void dvc_set_aes(void *user_data, uint8_t state)
{
    aes_enable(state);
}

void dvc_wakup(void *user_data)
{
    gpio_config_t io_conf = {
        .intr_type = GPIO_INTR_DISABLE,
        .mode = GPIO_MODE_OUTPUT,
        .pull_down_en = 0,
        .pull_up_en = 1,
        .pin_bit_mask = (1ULL << CONFIG_DVC1006_WAKUP)};
    gpio_config(&io_conf);
    gpio_set_level(CONFIG_DVC1006_WAKUP, 0);
    dvc_delay_ms(10);
    gpio_set_level(CONFIG_DVC1006_WAKUP, 1);
    dvc_delay_ms(50);
}

void IRAM_ATTR dvc_alert_isr(void *arg)
{
    dvc_alert(arg);
}

uint8_t dvc_set_config(void *user_data, const char *name, uint8_t *data, uint8_t len)
{
    if (config_set(name, len, data))
        return config_commit();
    return false;
}

uint8_t dvc_get_config(void *user_data, const char *name, uint8_t *data)
{
    if (!data)
        return 0;
    uint16_t len = config_get(name, NULL, 0);
    return config_get(name, data, len);
}
void dvc_new_data(void *p)
{
    dvc_t dvc = p;
    const uint16_t size = 1024;
    uint8_t *data = _malloc_(size);
    if (data)
    {
        uint16_t len = 0;
        char *str = (char *)data;
        len += sprintf(&str[len], "{");
        len += sprintf(&str[len], "\"api\":\"afe\",");
        len += sprintf(&str[len], "\"data\":");
        len += dvc_get_result_to(dvc, (uint8_t *)&str[len], size - len);
        len += sprintf(&str[len], "}");
        ws_send_msg(data, len);
        mqtt_send_msg(0, data, len, NULL, NULL);
        bemfa_send_msg(0, data, 1024, dvc, (mqtt_cb_t)dvc_get_result_to_bemfa);
        // printf("%s\n", (char *)data);
        free(data);
    }

    // if (dvc->alert)
    // {
    //     // dvc_clear_alert(dvc, DVC_EVENT_FLAG_AFE);
    //     printf("触发警报\n");
    //     // dvc->alert = 0;
    // }
}

#ifdef DVC_ENABLE_LOG
void dvc_push_log(void *p, uint8_t type, void *data_log, void *event_log)
{
    dvc_t dvc = p;
    char *buf = malloc(1024);
    if (!buf)
        return;
    uint16_t len = 0;
    char *str = (char *)buf;
    len += sprintf(&str[len], "{");
    len += sprintf(&str[len], "\"api\":\"log\",");
    len += sprintf(&str[len], "\"data\":{");
    if (data_log)
    {
        len += sprintf(&str[len], "\"type\":%d,", 0);
        len += sprintf(&str[len], "\"attr\":%d,", type);
        len += sprintf(&str[len], "\"content\":");
        len += dvc_log_print_to(dvc, data_log, &str[len], 1024 - len);
    }
    if (event_log)
    {
        len += sprintf(&str[len], "\"type\":%d,", 1);
        len += sprintf(&str[len], "\"content\":");
        len += dvc_log_event_print_to(dvc, event_log, &str[len], 1024 - len);
    }
    len += sprintf(&str[len], "}");
    len += sprintf(&str[len], "}");
    ws_send_msg((uint8_t *)buf, len);
    // printf("%s\n", buf);
    free(buf);
}
void dvc_save_log(uint8_t *log, uint8_t is_event)
{
    if (is_event)
        event_push(log, sizeof(dvc_log_event_t));
    else
        log_push(log, sizeof(dvc_log_t));
}
bool query_event_cb(fdb_tsl_t tsl, void *arg)
{
    struct fdb_blob blob = {0};
    dvc_log_event_t log = {0};
    fdb_tsdb_t db = arg;
    fdb_blob_read((fdb_db_t)db, fdb_tsl_to_blob(tsl, fdb_blob_make(&blob, &log, sizeof(log))));
    dvc_log_event_push_only(gloab_dvc, &log);
    // printf("push event: %lu\n", log.timestamp);
    return false;
}
bool query_log_cb(fdb_tsl_t tsl, void *arg)
{
    struct fdb_blob blob = {0};
    dvc_log_t log = {0};
    fdb_tsdb_t db = arg;
    fdb_blob_read((fdb_db_t)db, fdb_tsl_to_blob(tsl, fdb_blob_make(&blob, &log, sizeof(log))));
    dvc_log_record_years(gloab_dvc, &log);
    // printf("push log: %lu\n", log.timestamp);
    return false;
}
void dvc_get_logs(void *dvc)
{
    gloab_dvc = dvc;
    event_get_all(query_event_cb);
    log_get_all(query_log_cb);
}
#endif

#include <math.h>
float dvc_3950_ntc_get_temp(uint32_t temp_vol)
{
    // 常量
    const float Rp = 10000;
    const float T2 = 273.15f + 25.0f; // 25°C → K
    const float Bx = 3950.0f;         // B3950
    const float Ka = 273.15f;         // 开尔文换算
    const float Vref = 3.3f;

    // TSV 原始码值 → 电压 (mV)
    float Vt = temp_vol / 1000.0f; // 183.1 μV/bit → mV → V

    // 热敏电阻阻值
    // float Rt = (Vref - Vt) * Rp / Vt;/*  NTC 上拉接电源 */
    float Rt = Vt * Rp / (Vref - Vt); /*  NTC 下拉接地 */

    // Beta 公式换算成摄氏温度
    float temp_c = (1.0f / ((1.0f / T2) + (logf(Rt / Rp) / Bx))) - Ka;

    return temp_c;
}

void dvc_shutdown_save_data(void)
{
    dvc_hitstory_store(gloab_dvc);
#ifdef DVC_ENABLE_EVENT_LOG
    if (user_call_reboot) /* 用户手动复位 */
        dvc_log_event_record(gloab_dvc, DVC_EVENT_FLAG_USER, DVC_EVENT_TYPE_REBOOT, 0);
    else if (ota_default_handle && ota_default_handle->tick) /* 用户升级 - 系统复位  */
        dvc_log_event_record(gloab_dvc, DVC_EVENT_FLAG_AFE, DVC_EVENT_TYPE_REBOOT, 0);
    else /* 其它情况-异常复位 */
        dvc_log_event_record(gloab_dvc, DVC_EVENT_FLAG_AFE, DVC_EVENT_TYPE_REBOOT, 1);
#endif
}
void dvc_low_power(void *user_data, uint8_t type)
{
    if (type == DVC_LOW_POWER_TYPE_ENABLE)
    {
        aes_enable(false);
        wifi_del();
    }
    else if (type == DVC_LOW_POWER_TYPE_DISABLE)
    {
        wifi_init();
    }
    else if (type == DVC_LOW_POWER_TYPE_DEEP_SLEEP)
    {
        /* 芯片 置标志位 - 进入深度睡眠 - 定时唤醒 - 根据标志位动作  */
    }
}

static const dvc_ops_t dvc_ops = {
    .write_reg = dvc_write_reg,
    .read_reg = dvc_read_reg,
    .set_aes = dvc_set_aes,
    .save_config = dvc_set_config,
    .get_config = dvc_get_config,
    .delay_ms = dvc_delay_ms,
    .get_time = sntp_get_timestamp,
    .get_temp = dvc_3950_ntc_get_temp,
    .new_data = dvc_new_data,
#ifdef DVC_ENABLE_LOG
    .log_push = dvc_push_log,
    .save_log = dvc_save_log,
    .get_logs = dvc_get_logs,
#endif
    .low_power = dvc_low_power,
    .wakup = dvc_wakup,
    .user_data = &dvc_spi_handle,
};

void dvc_thread(void *p)
{
    while (1)
    {
        dvc_monitor(p);
        vTaskDelay(pdMS_TO_TICKS(33));
    }
}

void dvc1006_auto_init(void)
{
    spi_device_interface_config_t devcfg = {
        .command_bits = 0,
        .clock_speed_hz = CONFIG_DVC1006_SPI_FREQ * 1000,
        .mode = 3,
        .spics_io_num = CONFIG_DVC1006_CS,
        .queue_size = 1,
        .flags = SPI_DEVICE_HALFDUPLEX,
    };
    esp_err_t ret = spi_bus_add_device(SPI2_HOST, &devcfg, &dvc_spi_handle);
    if (ret != ESP_OK)
    {
        ESP_LOGE(TAG, "Failed to add DVC1006 device to SPI0 bus(%s)", esp_err_to_name(ret));
        return;
    }

    dvc_wakup(NULL);

    gloab_dvc = dvc_create(&dvc_ops, NULL);
    if (!gloab_dvc)
    {
        ESP_LOGE(TAG, "Failed to Create DVC Object.\n");
        return;
    }

    if (gloab_dvc->current_R < 0)
        dvc_cfg_print(&gloab_dvc->w_cfg, -gloab_dvc->current_R);
    else
        dvc_cfg_print(&gloab_dvc->w_cfg, gloab_dvc->current_R);

    // dvc_calib(gloab_dvc, 1.0f, 0.93f);

    /*  */
    const esp_timer_create_args_t dvc1006_tick_timer_args = {
        .arg = gloab_dvc,
        .callback = &increase_dvc1006_tick,
        .name = "dvc1006"};
    esp_timer_handle_t dvc1006_tick_timer = NULL;
    ESP_ERROR_CHECK(esp_timer_create(&dvc1006_tick_timer_args, &dvc1006_tick_timer));
    ESP_ERROR_CHECK(esp_timer_start_periodic(dvc1006_tick_timer, 2 * 1000));

    gpio_config_t int_io_conf = {
        .intr_type = GPIO_INTR_NEGEDGE,
        .mode = GPIO_MODE_INPUT,
        .pull_down_en = 0,
        .pull_up_en = 1,
        .pin_bit_mask = (1ULL << CONFIG_DVC1006_ALERT)};
    gpio_config(&int_io_conf);
    gpio_isr_handler_add(CONFIG_DVC1006_ALERT, dvc_alert_isr, gloab_dvc);

    xTaskCreate(dvc_thread, "dvc", 4096, gloab_dvc, 10, NULL);

    extern void dvc_api_init(void);
    dvc_api_init();

    esp_register_shutdown_handler((shutdown_handler_t)dvc_shutdown_save_data);
}